﻿#include "pch.h"
#include  <io.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include "cpptest.h"

#pragma warning(disable : 4996)    //注意这行，可能新的编译器提示有些函数如strlen，fopen等函数不安全
//可以换成更安全的函数，如fopen_s，也可以屏蔽这个警告

C_CFile::C_CFile()
{
	m_hFile = NULL;
	m_fname[0] = 0;
}
C_CFile::~C_CFile()
{
	Close();
}

short C_CFile::Open(const char * fname)
{
	//如果文件名为空或长度为0，则认为文件名非法
	if (!fname || strlen(fname)<1)
		return 0;
	//保存文件名
	strcpy(m_fname, fname);
	//如果文件已经被打开了，则把文件当前指针移到文件开始位置
	if (m_hFile)
	{
		fseek(m_hFile, 0, SEEK_SET);
		return 1;
	}
	if ((_access(fname, 0)) != -1) //文件存在，任意读写打开文件
		m_hFile = fopen(fname, "rb+");//
	else
		m_hFile = fopen(fname, "wb+"); //如果文件不存在，则通过写打开，创建一个新文件
									   //注意这种表达式
	return m_hFile ? 1 : 0;
}
//功能：从文件读数据
//buf：为从文件读出的数据存放空间，空间由调用该函数的使用者申请
//len：为读取数据的大小
short C_CFile::Read(char * buf, long len)
{
	//如果没有空间或读取的数据量不合法，则返回
	if (!m_hFile || !buf || len<1)
		return 0;
	/*
	fread函数
	buf		是读取的数据存放的内存的指针（可以是数组，也可以是新开辟的空间，buffer就是一个索引）   
	size	是每次读取的字节数  
	count	是读取次数  
	strean	是要读取的文件的指针  
	*/
	return fread(buf, len, 1, m_hFile);
}
//功能：数据写入到文件
//buf：准备写入文件的数据
//len：准备写入文件的数据的大小
short C_CFile::Write(const char * buf, long len)
{
	//如果没有空间或写入的数据量不合法，则返回
	if (!m_hFile || !buf || len<1)
		return 0;
	//用法参见fread
	fwrite(buf, len, 1, m_hFile);
	return 1;
}
void C_CFile::Close()
{
	if (m_hFile)
	{
		fclose(m_hFile);
		m_hFile = NULL;
	}
}
//移动文件指针当前位置
void C_CFile::SeekBegin()
{
	if (!m_hFile)
		return;
	fseek(m_hFile, 0, SEEK_SET);
}


C_CPPFile::C_CPPFile()
{

}
C_CPPFile::~C_CPPFile()
{

}

short C_CPPFile::Open(const char * fname)
{
	//文件名为空返回失败
	if (!fname || strlen(fname)<1)
		return 0;
	strcpy(m_fname, fname);
	//如果文件已经被打开了，则把文件当前指针移到文件开始位置
	if (m_hFile)
	{
		SeekBegin();
		return 1;
	}
	if ((_access(fname, 0)) != -1) //文件存在，任意读写打开文件
	{
		m_hFile.open(fname, ios::in | ios::out | ios::binary);
	}
	else
	{
		m_hFile.open(fname, ios::in | ios::out | ios::binary);
	}
	//注意这种表达式
	return m_hFile.is_open() ? 1 : 0;
}
//功能：从文件读数据
//buf：为从文件读出的数据存放空间，空间由调用该函数的使用者申请
//len：为读取数据的大小
short C_CPPFile::Read(char * buf, long len)
{
	//缓冲区非法
	if (!buf || len < 1)
		return 0;
	if (!m_hFile.is_open())
		return 0;
	if (!m_hFile.eof())
	{
		m_hFile.read(buf, len);
	}
	return 1;
}
//功能：数据写入到文件
//buf：准备写入文件的数据
//len：准备写入文件的数据的大小
short C_CPPFile::Write(const char * buf, long len)
{
	//缓冲区非法
	if (!buf || len < 1)
		return 0;
	if (!m_hFile.is_open())
		return 0;
	m_hFile.write((char *)buf, len);
	m_hFile.sync();
	return 1;
}
void C_CPPFile::Close()
{
	m_hFile.close();
}
//移动文件指针当前位置
void C_CPPFile::SeekBegin()
{
	if (!m_hFile.is_open())
		return;
	m_hFile.clear();
	m_hFile.seekp(0, ios::beg);
	m_hFile.seekg(0, ios::beg);
}


CBaseClass::CBaseClass()
{
	//m_hFile = NULL;
	//m_fname[0] = 0;
}
CBaseClass::~CBaseClass()
{
	//Close();
}

//////
CStudent::CStudent()
{
	m_pStud = new student_inf[100];//初始化为100
	m_len = 100;
	m_num = 0;
	OpenFile();//打开文件
}
CStudent::~CStudent()
{
	if (m_pStud)
		delete[] m_pStud;//释放申请的空间
	m_len = 0;
	m_num = 0;
	CloseFile();//关闭文件
}
short CStudent::Add(student_inf &stud)
{
	if (m_len == m_num)//没有多余空间时
	{
		student_inf * pNewStud = new student_inf[m_len += 100];//每次增大100
		if (!pNewStud)
			return 0;
		memcpy(pNewStud, m_pStud, sizeof(student_inf)*m_num);  //将数据赋值到新数组
		delete[] m_pStud;   //删除老数组
		m_pStud = pNewStud; //把新数组地址赋给老数组
	}
	m_pStud[m_num] = stud;//考虑赋值重载
	m_num++;
	return 1;
}

short CStudent::Del(char *no)
{
	int index = Ask(no, NULL);
	if (index < 0) //查找失败
		return 0;
	if (index == m_num - 1)//最后一个
	{
		m_num--;
		return 1;
	}
	//从删除的序号开始，把后面的数据前移
	/*
	如下，数组中共有13个数，序号0-12
	|_0_|_1_|_2_|_3_|_4_|_5_|_*6*_|_7_|_8_|_9_|_10_|_11_|_12_|
	假设删除*6*这个，在数组中其序号为6，Ask函数返回是6，其实是第7个，m_pStud+6表示移动地址到*6*，m_pStud + 6 + 1表示从7的位置开始，后面的数据向前移动一个单元
	*/
	memcpy(m_pStud + index, m_pStud + index + 1, sizeof(student_inf)*(m_num - index - 1));
	m_num--;

	return 1;
}
short CStudent::Update(char * no, student_inf &stud)
{
	int index = Ask(no, NULL);
	if (index < 0)//查找失败
		return 0;
	m_pStud[index] = stud;//考虑赋值重载
	return 1;
}
//学号唯一
short CStudent::Ask(char * no, student_inf *stud)
{
	int index = -1;
	if (!no)
		return index;
	for (int i = 0; i<m_num; i++)
	{
		if (strcmp(m_pStud[i].no, no) != 0)
			continue;
		index = i;
		if (stud)
			*stud = m_pStud[i]; //考虑赋值重载
		break;
	}
	return index;
}
short CStudent::OpenFile()
{
	return Open("d:\\test\\stud.txt");//固定了路径，如果不固定，可以取路径
}
/*
需要注意，如果要读文件中的内容，在需要先了解文件的格式
假设我们文件按照如下格式存放
(student_inf)(student_inf)(student_inf)(student_inf)(student_inf)(student_inf)......
那么
我们从文件读的时候，就可以按照student_inf大小一个一个读
当然，我们也可以如此存放
(long)(student_inf)(student_inf)(student_inf)(student_inf)(student_inf)(student_inf)......
即：第一long存储有多少个student_inf，这样就可以一下读取多个student_inf了
*/
short CStudent::ReadData()
{
	//以下为一个一个读
	student_inf inf;
	short numread = 0;
	numread = Read((char*)&inf, sizeof(student_inf));
	if (numread < 1)
		return 0;
	while (numread)
	{
		Add(inf);
		numread = Read((char*)&inf, sizeof(student_inf));
	}
	return 1;
}
short CStudent::WriteData()
{
	if (!m_pStud || m_num < 1)
		return 0;
	SeekBegin();//先把文件的当前位置指针移动到文件最开始，也就是，每次写文件，都从文件最开始写，也就是覆盖内容
				//一次写多个
	Write((char*)m_pStud, sizeof(student_inf)*m_num);
	/*每次写一个
	for(int i = 0;i<m_num;i++)
	{
	Write((char*)&m_pStud[i], sizeof(student_inf));
	}
	*/
	return 1;
}
void CStudent::CloseFile()
{
	Close();
}
//取学生数据，注意pLst是双指针，返回m_pStud数组地址，num返回m_num的值
//short CStudent::GetData(student_inf ** pLst, long * num)
short CStudent::GetData(void ** pLst, long * num)
{
	if (!pLst || !num)
		return 0;
	*pLst = (void*)m_pStud;
	*num = m_num;
	return 1;
}

//////
CCourse::CCourse()
{
	m_pCour = new course_inf[100];//初始化为100
	m_len = 100;
	m_num = 0;
	OpenFile();//打开文件
}
CCourse::~CCourse()
{
	if (m_pCour)
		delete[] m_pCour;//释放申请的空间
	m_len = 0;
	m_num = 0;
	CloseFile();//关闭文件
}
short CCourse::Add(course_inf &cour)
{
	if (m_len == m_num)//没有多余空间时
	{
		course_inf * pNewCour = new course_inf[m_len += 100];//每次增大100
		if (!pNewCour)
			return 0;
		memcpy(pNewCour, m_pCour, sizeof(course_inf)*m_num);  //将数据赋值到新数组
		delete[] m_pCour;   //删除老数组
		m_pCour = pNewCour; //把新数组地址赋给老数组
	}
	m_pCour[m_num] = cour;//考虑赋值重载
	m_num++;
	return 1;
}

short CCourse::Del(char *no)
{
	return 0;
}
short CCourse::Update(char * no, course_inf &cour)
{
	return 0;
}
//课程号唯一
short CCourse::Ask(char * no, course_inf *cour)
{
	int index = -1;
	if (!no)
		return index;
	for (int i = 0; i<m_num; i++)
	{
		if (strcmp(m_pCour[i].no, no) != 0)
			continue;
		index = i;
		if (cour)
			*cour = m_pCour[i]; //考虑赋值重载
		break;
	}
	return index;
}
short CCourse::OpenFile()
{
	return Open("d:\\test\\cour.txt");//固定了路径，如果不固定，可以取路径
}
/*
需要注意，如果要读文件中的内容，在需要先了解文件的格式
1、假设我们文件按照如下格式存放
(course_inf)(course_inf)(course_inf)(course_inf)(course_inf)(course_inf)......
那么
我们从文件读的时候，就可以按照course_inf大小一个一个读
2、假设我们文件按照如下格式存放
(long)(course_inf)(course_inf)(course_inf)(course_inf)(course_inf)(course_inf)......
即：第一long存储有多少个course_inf，这样就可以一下读取多个course_inf了

下面的示例按照第2种方法
*/
short CCourse::ReadData()
{
	//从头开始
	SeekBegin();
	//先读数据的大小，这个和写函数对照
	char buf[10] = "0";
	Read(buf, sizeof(long));
	m_num = atol(buf);
	//以下为读多个
	Read((char*)m_pCour, sizeof(course_inf)*(m_num>m_len ? m_len : m_num));
	return 1;
}
short CCourse::WriteData()
{
	if (!m_pCour || m_num < 1)
		return 0;
	SeekBegin();//先把文件的当前位置指针移动到文件最开始，也就是，每次写文件，都从文件最开始写，也就是覆盖内容
				//一次写多个
				//先写大小，要注意，读数据要先读大小
	char buf[10] = "0";
	_ltoa(m_num, buf, 10);
	Write(buf, sizeof(long));
	//写内容
	Write((char*)m_pCour, sizeof(course_inf)*m_num);
	return 1;
}
void CCourse::CloseFile()
{
	Close();
}

//取学生数据，注意pLst是双指针，返回m_pCour数组地址，num返回m_num的值
//short CCourse::GetData(course_inf ** pLst, long * num)
short CCourse::GetData(void ** pLst, long * num)
{
	if (!pLst || !num)
		return 0;
	*pLst = (void*)m_pCour;
	*num = m_num;
	return 1;
}
/////////////////////////
CScore::CScore()
{
	m_pStuObj = new CStudent(); //学生对象
	m_pCourObj = new CCourse(); //课程对象
	m_pScor = new score_inf[100];//初始化为100
	m_len = 100;
	m_num = 0;
	OpenFile();//打开文件
}
CScore::~CScore()
{
	if (m_pScor)
		delete[] m_pScor;//释放申请的空间
	m_len = 0;
	m_num = 0;
	delete m_pStuObj;
	delete m_pCourObj;
	CloseFile();//关闭文件
}

short CScore::OpenFile()
{
	return Open("d:\\test\\scor.txt");//固定了路径，如果不固定，可以取路径
}
short CScore::ReadData()
{
	return 0;
}
short CScore::WriteData()
{
	//只写一个文件
	return 0;
}
void CScore::CloseFile()
{
	//同时关闭三个文件
}
short CScore::Add(score_inf &scor)
{
	return 0;
}
short CScore::Del(char * sno, char * cno)
{
	return 0;
}
short CScore::Update(char * sno, char * cno, score_inf &scor)
{
	return 0;
}
short CScore::Ask(char * sno, char * cno, score_inf *scor)
{
	return 0;
}